package br.uefs.dexa.rfframework.gui.impl;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.lang.reflect.InvocationTargetException;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JTextPane;
import javax.swing.SwingConstants;
import javax.swing.WindowConstants;

import br.uefs.dexa.rfframework.gui.interfaces.RFUserGUI;
import br.uefs.dexa.rfframework.gui.utils.CustomMenuBar;
import br.uefs.dexa.rfframework.gui.utils.ScreenUtils;
import br.unicamp.ic.lis.rfframework.objects.DigitalObject;
import br.unicamp.ic.lis.rfframework.objects.DigitalObjectSet;
import br.unicamp.ic.lis.rfframework.objects.IDigitalObject;
import br.unicamp.ic.lis.rfframework.objects.LabeledDigitalObject;


public class SimpleRFUserGUI extends RFUserGUI {
	
	private static final int SCROLL_BAR_UNIT_INCREMENT = 35;
	
	private static final int CONTAINER_BORDER = 5;
	
	private static final int TOP_PANEL_HEIGTH = 400;
	
	private static final int PANELS_WIDTH = 1000;
	
	private static final float PROGRESS_BAR_LABEL_FONT_SIZE = 18.0f;
	
	private static final int PROGRESS_BAR_WIDTH = 300;
	
	private static final int PROGRESS_BAR_HEIGTH = 30;
	
	private static SimpleRFUserGUI instance;

	
	//top level window
	private JFrame window;
	
	//menu bar
	private CustomMenuBar menuBar;
	
	//layout organization panels
	private JPanel layoutTopPanel;
	private JPanel layoutBottomPanel;
	
	//tabbed panes 
	private JTabbedPane queryPatternPane;
	private JTabbedPane relevantObjectsPane;
	private JTabbedPane outputPane;
	
	//scroll panes
	private JScrollPane queryScrollPane;
	private JScrollPane relevantsScrollPane;
	private JScrollPane outputScrollPane;
	
	//split panes
	private JSplitPane topHorizontalSplitPane;
	private JSplitPane windowVerticalSplitPane;
	
	//progress bar
	private JDialog dialog;	
	private JProgressBar progressBar;
	private Thread progressBarThread;
	
	//teste
	private JTextField statusPane; 
	
	private boolean userIndicatedSatisfaction = false;
	
	private boolean userSatisfied = false;

	
	
	private SimpleRFUserGUI()
	{
		super();
	}
	
	public static synchronized SimpleRFUserGUI getInstance()
	{
		if (instance == null) {
			try {
				EventQueue.invokeAndWait(new Runnable() {
					public void run() {
						instance = new SimpleRFUserGUI();
					}
				});
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		return instance;
	}
	
	@Override
	protected void compose() 
	{
		buildUi();
		window.pack();
		window.setVisible(true);
	}
	
	@Override
	protected boolean getUserSatisfaction()
	{
//		return JOptionPane
//				.showOptionDialog(layoutTopPanel, "Are you satisfied?", "RFEngine",
//						JOptionPane.YES_NO_OPTION,
//						JOptionPane.QUESTION_MESSAGE, null, null,
//						JOptionPane.NO_OPTION) == JOptionPane.YES_OPTION;
		
		getObjectSetVisualizationPanel().relevanceFeedbackMode();
		
		//statusPane.setText("Click Finish or indicate relevant images.");
		statusPane.setText("Select relevant images or finish.");
		statusPane.setForeground(Color.BLUE);
		statusPane.revalidate();
		statusPane.repaint();
		
		return waitsForUserSatisfactionAnswer();
		
	}
	
	//Guarded block (see http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html)
	private synchronized boolean waitsForUserSatisfactionAnswer()
	{

		userIndicatedSatisfaction = false; 
		
		while(!userIndicatedSatisfaction) 
		{			
			try {
	            wait();
	        } catch (InterruptedException e) {}
		}

		userIndicatedSatisfaction = false; //reset for future new query
		
		getObjectSetVisualizationPanel().neutralMode();
		//getObjectSetVisualizationPanel().queryPatternMode();
		
		
		return userSatisfied;
	}
	
	@Override
	public void addRelevantObject(IDigitalObject object)
	{
		super.addRelevantObject(object);
		
		if(getRelevantObjectsPanel().getObjectsSize() == 1)
			userIndicatedSatisfaction(true);
	}
	
	@Override
	public void removeRelevantObject(IDigitalObject object)
	{
		super.removeRelevantObject(object);
//		if(getRelevantObjectsPanel().getObjectsSize() == 0)
//			getRelevantObjectsPanel().disableTriggerComponent();
	}
	
	@Override
	public void finalize()
	{
		//getObjectSetVisualizationPanel().finalize();
		statusPane.setText("Process Finished.");
		statusPane.setForeground(Color.BLUE);
		statusPane.revalidate();
		statusPane.repaint();
	}
	
	public synchronized void userIndicatedSatisfaction(boolean value)
	{
		this.userIndicatedSatisfaction = value;
		notifyAll();
	}
	
	@Override
	public void userSatisfaction(boolean value)
	{
		this.userSatisfied = value;
		userIndicatedSatisfaction(true);
	}
	
	@Override
	public void startRFProgressViewer()
	{		
		progressBarThread = new Thread(new Runnable() {
			@Override
			public void run() {
				setupProgressDialog();
			}
		});
		progressBarThread.start();
		
	}
	
	private void setupProgressDialog()
	{
	
    	try {
			EventQueue.invokeAndWait(new Runnable() {
				
				@Override
				public void run() {
					
					progressBar = new JProgressBar();
					progressBar.setPreferredSize(new Dimension(PROGRESS_BAR_WIDTH, PROGRESS_BAR_HEIGTH));
				    progressBar.setMaximumSize(new Dimension(PROGRESS_BAR_WIDTH, PROGRESS_BAR_HEIGTH));

					Thread t = new Thread(new Runnable() {
						@Override
						public void run() {
							progressBar.setIndeterminate(true);
						}
					});
					t.start();

		    		
		    		JPanel dialogPanel = new JPanel();
		    		dialogPanel.setLayout(new BorderLayout());
		    		
		    		dialogPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
		    		JLabel label = new JLabel("retrieving...", SwingConstants.CENTER);
		    		label.setFont (label.getFont ().deriveFont (PROGRESS_BAR_LABEL_FONT_SIZE));
		    		label.setBorder(BorderFactory.createEmptyBorder(0, 0, 5, 0));
		    		dialogPanel.add(label, BorderLayout.NORTH);
		    		dialogPanel.add(progressBar, BorderLayout.SOUTH);
		         
		    		
		    		
		    		dialog = new JDialog(null, "", Dialog.ModalityType.DOCUMENT_MODAL);
		    		dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		            
		            dialog.setModal(true);
		            dialog.add(dialogPanel);
		        	dialog.pack();
		        	dialog.setLocation((ScreenUtils.getHalfWidth() - dialog.getWidth()/2) + 35 , (ScreenUtils.getHalfHeigth() - dialog.getHeight()/2));
		        	dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
		        	dialog.setTitle("RFEngine");
		        	dialog.setVisible(true);
				}
			});
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

	}
	
	
	@Override
	public void finalizeRFProgressViewer()
	{
		hideProgressDialog();	
	}
	
	private void hideProgressDialog()
	{

		try {
			EventQueue.invokeAndWait(new Runnable() {
				public void run() {
					progressBar.setIndeterminate(false);
					dialog.dispose();
					progressBarThread = null;
					
					dialog.removeAll();
					dialog.setVisible(false);
					//dialog = null;
					dialog = new JDialog(null, "", Dialog.ModalityType.DOCUMENT_MODAL);
					progressBar = null;
				}
			});
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		
	}
	
	private void buildUi() 
	{
		buildWindow();
		//buildMenu();
		buildLayoutPanels();
		buildPanes();
		putEverythingTogether();
	}
	
	private void buildWindow()
	{
		window = new JFrame("RFEngine");
		window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		window.setLayout(new BoxLayout(window.getContentPane(), BoxLayout.PAGE_AXIS));
		window.setExtendedState(JFrame.MAXIMIZED_BOTH);
	}
	
	
	private void buildPanes()
	{
		buildQueryPatternPane();
		buildRelevantObjectsPane();
		buildOutputPane();
		buildScrollPanes();
		buildSplitPanes();
	}
	
	private void buildLayoutPanels()
	{
		buildTopPanel();
		buildBottomPanel();
	}
	
	private void buildTopPanel()
	{
		layoutTopPanel = new JPanel();
		layoutTopPanel.setPreferredSize(new Dimension(PANELS_WIDTH, TOP_PANEL_HEIGTH));
		layoutTopPanel.setLayout(new BoxLayout(layoutTopPanel, BoxLayout.LINE_AXIS));
	}
	
	private void buildBottomPanel()
	{
		layoutBottomPanel = new JPanel();
		layoutBottomPanel.setLayout(new BoxLayout(layoutBottomPanel, BoxLayout.PAGE_AXIS));
	}
	
	private void buildQueryPatternPane()
	{
		queryPatternPane = new JTabbedPane();
		queryPatternPane.add(super.getQueryPatternPanel());
		queryPatternPane.setTitleAt(0, "Query Pattern");
		queryPatternPane.setBorder(BorderFactory.createEmptyBorder(CONTAINER_BORDER, CONTAINER_BORDER, CONTAINER_BORDER, 0));
	}

	private void buildRelevantObjectsPane()
	{
		relevantObjectsPane = new JTabbedPane();
		relevantObjectsPane.add(super.getRelevantObjectsPanel());
		relevantObjectsPane.setTitleAt(0, "Relevant Objects");
		relevantObjectsPane.setBorder(BorderFactory.createEmptyBorder(CONTAINER_BORDER, CONTAINER_BORDER, CONTAINER_BORDER, CONTAINER_BORDER));
	}
	
	private void buildOutputPane()
	{
		outputPane = new JTabbedPane();
		outputPane.add(super.getObjectSetVisualizationPanel());
		outputPane.setTitleAt(0, "Output");
		outputPane.setBorder(BorderFactory.createEmptyBorder(CONTAINER_BORDER, CONTAINER_BORDER, CONTAINER_BORDER, CONTAINER_BORDER));		
	}
	
	
	private void buildScrollPanes()
	{
		queryScrollPane = new JScrollPane(queryPatternPane);
		relevantsScrollPane = new JScrollPane(relevantObjectsPane);
		outputScrollPane = new JScrollPane(outputPane);
		outputScrollPane.getVerticalScrollBar().setUnitIncrement(SCROLL_BAR_UNIT_INCREMENT);
		outputScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
	}
	

	private void buildSplitPanes()
	{
		//topHorizontalSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, queryScrollPane, relevantsScrollPane);
		topHorizontalSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, queryPatternPane, relevantObjectsPane);
		
		windowVerticalSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, layoutTopPanel, layoutBottomPanel);
		topHorizontalSplitPane.setDividerLocation(ScreenUtils.getHalfWidth() - 100);
		windowVerticalSplitPane.setDividerLocation(ScreenUtils.getHalfHeigth() - 200);
	}
	
	
	private void putEverythingTogether()
	{
		layoutTopPanel.add(topHorizontalSplitPane);
		
		JPanel statusPanel = new JPanel();
		statusPanel.setPreferredSize(new Dimension(500, 40));
		statusPanel.setMaximumSize(new Dimension(500, 40));
		
		statusPane = new JTextField();
		statusPane.setPreferredSize(new Dimension(500, 30));
		statusPane.setMaximumSize(new Dimension(500, 30));
		//statusPane.setFont(new Font("Verdana", Font.BOLD, 18));
		//statusPane.setFont(new Font("Arial", Font.BOLD, 18));
		statusPane.setFont(new Font("Arial", Font.PLAIN, 18));
		statusPane.setHorizontalAlignment(JTextField.CENTER);
		statusPane.setEditable(false);
		
		statusPanel.add(statusPane);
		layoutBottomPanel.add(statusPanel);
		
		layoutBottomPanel.add(outputScrollPane);
		
		menuBar = new CustomMenuBar();
		window.setJMenuBar(menuBar);
		window.add(windowVerticalSplitPane);
	}
	
	@Override
	public DigitalObjectSet<LabeledDigitalObject> indicationOfQueryPattern(
			DigitalObjectSet<DigitalObject> collection) {
		
		statusPane.setText("Select query images and click Run.");
		statusPane.setForeground(new Color(0, 153, 0));
		statusPane.revalidate();
		statusPane.repaint();
		
		return super.indicationOfQueryPattern(collection);
	}
	
	@Override
	public DigitalObjectSet<LabeledDigitalObject> userIndicationOfObjectsRelevance(
			DigitalObjectSet<DigitalObject> retrievedObjects,
			DigitalObjectSet<LabeledDigitalObject> queryPattern) { // obs: retrievedObjects and queryPattern not used  
		
		statusPane.setText("Select relevant images and submit.");
		//statusPane.setForeground(Color.ORANGE);
		statusPane.setForeground(new Color(255, 128, 0));
		statusPane.revalidate();
		statusPane.repaint();
		
		return super.userIndicationOfObjectsRelevance(retrievedObjects, queryPattern);
	}
	
	public boolean showSetOfObjects(
			DigitalObjectSet<DigitalObject> retrievedObjects) {
	
		statusPane.setText("");
		statusPane.setForeground(Color.BLACK);
		statusPane.revalidate();
		statusPane.repaint();
		
		return super.showSetOfObjects(retrievedObjects);		
	}
	
}
